#include "msgqueue.h"

// Allocate a message stack
MESSAGE_STACK* MsgAllocStack() { return new MESSAGE_STACK(); }

// Free a message stack
void MsgFreeStack(MESSAGE_STACK* Stack) {
  ASSERT_NONNULL(Stack);

  // Update termination variable
  Stack->Destroy = true;

  // Notify each thread
  for (int i = 0; i < Stack->WaitingCalls + 1;
       i++)  // TODO: found crash here on exit
  {
    MESSAGE newMessage;
    Stack->msgs.enqueue(newMessage);
  }

  // Delete allocated structure
  // delete Stack;
}

// Add a message to the stack
bool MsgSend(MESSAGE_STACK* Stack, int Msg, duint Param1, duint Param2) {
  if (Stack->Destroy) return false;

  MESSAGE newMessage;
  newMessage.msg = Msg;
  newMessage.param1 = Param1;
  newMessage.param2 = Param2;

  // Asynchronous send
  asend(Stack->msgs, newMessage);
  return true;
}

// Get a message from the stack (will return false when there are no messages)
bool MsgGet(MESSAGE_STACK* Stack, MESSAGE* Msg) {
  if (Stack->Destroy) return false;

  // Don't increment the wait count because this does not wait
  return try_receive(Stack->msgs, *Msg);
}

// Wait for a message on the specified stack
void MsgWait(MESSAGE_STACK* Stack, MESSAGE* Msg) {
  if (Stack->Destroy) return;

  // Increment/decrement wait count
  InterlockedIncrement((volatile long*)&Stack->WaitingCalls);
  *Msg = Stack->msgs.dequeue();
  InterlockedDecrement((volatile long*)&Stack->WaitingCalls);
}
